package com.group9.handinhand.dao;

import java.io.Serializable;
import java.util.List;

import org.springframework.stereotype.Repository;

import com.group9.handinhand.dao.model.Community;
import com.group9.handinhand.dao.model.CommunityTag;
import com.group9.handinhand.dao.model.Event;
import com.group9.handinhand.dao.model.EventTag;
import com.group9.handinhand.dao.model.Offer;
import com.group9.handinhand.dao.model.OfferTag;
import com.group9.handinhand.dao.model.Request;
import com.group9.handinhand.dao.model.RequestTag;
import com.group9.handinhand.dao.model.Tag;
import com.group9.handinhand.dao.model.User;
import com.group9.handinhand.dao.model.UserTag;
/**
 *class for Tag Dao
 *
 */
@Repository
public class TagDao extends BaseDaoImpl {
	/**
	 * finds all tags in tag class
	 * @return
	 */
	public List<Tag> findAllTags() {		
		return findAll(Tag.class);
	}
	/**
	 * saves tag
	 * @param tag
	 */
	public void saveTag(Tag tag) {
		save(tag);
	}
	/**
	 * finds tag by tag id
	 * @param id
	 * @return
	 */
	public Tag findTagById(Serializable id) {
		return (Tag) findById(Tag.class, id);
	}
	/**
	 * finds tag by tag's name
	 * @param tagName
	 * @return
	 */
	public Tag findTagByName(String tagName) {
		return findEntityByPropertyUnique(Tag.class, "tagName", tagName);
	}
	
	public void saveUserTag(UserTag userTag) {
		save(userTag);
	}
	/**
	 * finds all tags associated to a user
	 * @param userId
	 * @return
	 */
	public List<Tag> findTagsByRelatedUserId(Serializable userId) {
		String queryString = "Select distinct (ut.tag) from UserTag ut inner join ut.user us where us.id =:userId";
		return executeQueryString(queryString, "userId", userId);
	}
	/**
	 * finds a tag related to a user with its tag id
	 * @param tag
	 * @param user
	 * @return
	 */
	public UserTag findUserTagByTagIdandUserId(Tag tag, User user) {
		String [] properties = {"tag","user"};
		Object [] values = {tag, user };
		return findEntityByPropertyUnique(UserTag.class, properties, values);
	}
	/**
	 * finds all tags associated to a user 
	 * @param user
	 * @return
	 */
	public List<UserTag> findUserTagsByUser(User user) {
		return findEntityByProperty(UserTag.class, "user", user);
	}
	/**
	 * deletes a user tag
	 * @param userTag
	 */
	public void deleteUserTag(UserTag userTag) {
		userTag = findEntityByPropertyUnique(UserTag.class, "id", userTag.getId());
		delete(userTag);
	}
	/**
	 * finds all the tags related to a community
	 * @param communityId
	 * @return
	 */
	public List<Tag> findTagsByRelatedCommunityId(long communityId) {
		String queryString = "Select distinct (ct.tag) from CommunityTag ct inner join ct.community co where co.id =:communityId";
		return executeQueryString(queryString, "communityId", communityId);
	}
	/**
	 * finds a community tag using the community id and the tag id
	 * @param tag
	 * @param community
	 * @return
	 */
	public CommunityTag findCommunityTagByTagIdandCommunityId(Tag tag, Community community) {
		String [] properties = {"tag","community"};
		Object [] values = {tag, community };
		return findEntityByPropertyUnique(CommunityTag.class, properties, values);
	}

	public void saveCommunityTag(CommunityTag communityTag) {
		save(communityTag);
	}
	/**
	 * finds the tags related to a community
	 * @param community
	 * @return
	 */
	public List<CommunityTag> findCommunityTagsByCommunity(Community community) {
		return findEntityByProperty(CommunityTag.class, "community", community);
	}

	public void deleteCommunityTag(CommunityTag communityTag) {
		communityTag = findEntityByPropertyUnique(CommunityTag.class, "id", communityTag.getId());
		delete(communityTag);	
	}
	/**
	 * finds the tags of an event
	 * @param eventId
	 * @return
	 */
	public List<Tag> findTagsByRelatedEventId(long eventId) {
		String queryString = "Select distinct (et.tag) from EventTag et inner join et.event eo where eo.id =:eventId";
		return executeQueryString(queryString, "eventId", eventId);
	}
	/**
	 * finds event tag using the event id
	 * @param tag
	 * @param event
	 * @return
	 */
	public EventTag findEventTagByTagIdandEventId(Tag tag, Event event) {
		String [] properties = {"tag","event"};
		Object [] values = {tag, event };
		return findEntityByPropertyUnique(EventTag.class, properties, values);
	}

	public void saveEventTag(EventTag eventTag) {
		save(eventTag);		
	}
	/**
	 * finds event tags
	 * @param event
	 * @return
	 */
	public List<EventTag> findEventTagsByCEvent(Event event) {
		return findEntityByProperty(EventTag.class, "event", event);
	}

	public void deleteEventTag(EventTag eventTag) {
		eventTag = findEntityByPropertyUnique(EventTag.class, "id", eventTag.getId());
		delete(eventTag);	
	}
	/**
	 * finds tags related to an offer
	 * @param offerId
	 * @return
	 */
	public List<Tag> findTagsByRelatedOfferId(long offerId) {
		String queryString = "Select distinct (ot.tag) from OfferTag ot inner join ot.offer oo where oo.id =:offerId";
		return executeQueryString(queryString, "offerId", offerId);
	}
	/**
	 * finds an offer tag using offer id
	 * @param tag
	 * @param offer
	 * @return
	 */
	public OfferTag findOfferTagByTagIdandOfferId(Tag tag, Offer offer) {
		String [] properties = {"tag","offer"};
		Object [] values = {tag, offer };
		return findEntityByPropertyUnique(OfferTag.class, properties, values);
	}

	public OfferTag saveOfferTag(OfferTag offerTag) {
		save(offerTag);	
		return offerTag;
	}
	/**
	 * finds tags of an offer
	 * @param offer
	 * @return
	 */
	public List<OfferTag> findOfferTagsByCOffer(Offer offer) {
		return findEntityByProperty(OfferTag.class, "offer", offer);
	}
	/**
	 * deletes related offer tag
	 * @param offerTag
	 */
	public void deleteOfferTag(OfferTag offerTag) {
		offerTag = findEntityByPropertyUnique(OfferTag.class, "id", offerTag.getId());
		delete(offerTag);	
	}
	/**
	 * deletes related request tag
	 * @param requestTag
	 */
	public void deleteRequestTag(RequestTag requestTag) {
		requestTag = findEntityByPropertyUnique(RequestTag.class, "id", requestTag.getId());
		delete(requestTag);
	}
	/**
	 * saves the tag of a specific request
	 * @param requestTag
	 * @return
	 */
	public RequestTag saveRequestTag(RequestTag requestTag) {
		save(requestTag);
		return requestTag;
	}
	/**
	 * finds the tag of a request 
	 * @param request
	 * @return
	 */
	public List<RequestTag> findRequestTagsByRequest(Request request) {
		return findEntityByProperty(RequestTag.class, "request", request);
	}
	/**
	 * finds request tag using the tag id and request id 
	 * @param tag
	 * @param request
	 * @return
	 */
	public RequestTag findRequestTagByTagIdandRequestId(Tag tag, Request request) {
		String [] properties = {"tag","request"};
		Object [] values = {tag, request };
		return findEntityByPropertyUnique(RequestTag.class, properties, values);
	}
	/**
	 * finds all tags related to a request
	 * @param requestId
	 * @return
	 */
	public List<Tag> findTagsByRelatedRequestId(long requestId) {
		String queryString = "Select distinct (rt.tag) from RequestTag rt inner join rt.request re where re.id =:requestId";
		return executeQueryString(queryString, "requestId", requestId);
	}

}
